#include "AdminTools.h"

int	AgoraAdmin::Tools::HexPairValue(const char * code)
{
	int value = 0;
	const char * pch = code;
	for (;;) {
		int digit = *pch++;
		if (digit >= '0' && digit <= '9') {
			value += digit - '0';
		}
		else if (digit >= 'A' && digit <= 'F') {
			value += digit - 'A' + 10;
		}
		else if (digit >= 'a' && digit <= 'f') {
			value += digit - 'a' + 10;
		}
		else {
			return -1;
		}
		if (pch == code + 2)
			return value;
		value <<= 4;
	}
}

int	AgoraAdmin::Tools::UrlDecode(const char *source, char *dest)
{
  char * start = dest;

  while (*source) {
    switch (*source) {
    case '+':
      *(dest++) = ' ';
      break;
    case '%':
      if (source[1] && source[2]) {
        int value = HexPairValue(source + 1);
        if (value >= 0) {
          *(dest++) = value;
          source += 2;
        }
        else {
          *dest++ = '?';
        }
      }
      else {
        *dest++ = '?';
      }
      break;
    default:
      *dest++ = *source;
    }
    source++;
  }
  
  *dest = 0;
  return dest - start;
}  

int	AgoraAdmin::Tools::UrlEncode(const char *source, char *dest, unsigned max)  
{
  static const char *digits = "0123456789ABCDEF";
  unsigned char ch;
  unsigned len = 0;
  char *start = dest;

  while (len < max - 4 && *source)
  {
    ch = (unsigned char)*source;
    if (*source == ' ') {
      *dest++ = '+';
    }
    else if (isalnum(ch))
	{// || strchr("-_.!~*'()", ch)) {
      *dest++ = *source;
    }
    else {
      *dest++ = '%';
      *dest++ = digits[(ch >> 4) & 0x0F];
      *dest++ = digits[       ch & 0x0F];
    }  
    source++;
  }
  *dest = 0;
  return start - dest;
}

std::string	AgoraAdmin::Tools::UrlDecodeString(const std::string& encoded)
{
	const char * sz_encoded = encoded.c_str();
	size_t needed_length = encoded.length();
	for (const char * pch = sz_encoded; *pch; pch++)
	{
		if (*pch == '%')
			needed_length += 2;
	}
	needed_length += 10;
	char stackalloc[64];
	char * buf = needed_length > sizeof(stackalloc) / sizeof(*stackalloc) ? (char *)malloc(needed_length) : stackalloc;
	UrlDecode(encoded.c_str(), buf);
	std::string result(buf);
	if (buf != stackalloc)
		free(buf);
	return result;
}

std::string	AgoraAdmin::Tools::UrlEncodeString(const std::string& decoded)
{
	const char * sz_decoded = decoded.c_str();
	size_t needed_length = decoded.length() * 3 + 3;
	char stackalloc[64];
	char * buf = needed_length > sizeof(stackalloc) / sizeof(*stackalloc) ? (char *)malloc(needed_length) : stackalloc;
	UrlEncode(decoded.c_str(), buf, needed_length);
	std::string result(buf);
	if (buf != stackalloc)
		free(buf);
	return result;
}
